package com.haoxi.gateway.test.gatewayserver;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.haoxi.gateway.common.TestConfConst;
import com.haoxi.gateway.test.CMPPConstant;
import com.haoxi.gateway.test.SGIPConstant;
import com.haoxi.gateway.test.message.CMPP30ActiveTest;
import com.haoxi.gateway.test.message.CMPP30ActiveTestRep;
import com.haoxi.gateway.test.message.CMPP30ConnectMessage;
import com.haoxi.gateway.test.message.CMPP30ConnectRepMessage;
import com.haoxi.gateway.test.message.CMPP30DeliverMessage;
import com.haoxi.gateway.test.message.CMPP30DeliverRepMessage;
import com.haoxi.gateway.test.message.CMPP30StatusRpt;
import com.haoxi.gateway.test.message.CMPP30SubmitMessage;
import com.haoxi.gateway.test.message.CMPP30SubmitRepMessage;
import com.haoxi.gateway.test.message.SGIPActiveTestMessage;
import com.haoxi.gateway.test.message.SGIPActiveTestRepMessage;
import com.haoxi.gateway.test.message.SGIPBindMessage;
import com.haoxi.gateway.test.message.SGIPBindRepMessage;
import com.haoxi.gateway.test.message.SGIPReportMessage;
import com.haoxi.gateway.test.message.SGIPSubmitMessage;
import com.haoxi.gateway.test.message.SGIPSubmitRepMessage;
import com.haoxi.gateway.test.util.SecurityTools;
import com.haoxi.gateway.test.util.TypeConvert;

/**
 * 
 * 
 * 接受和处理SP发送过来消息的主类 Revision History
 * 
 * Jun 22, 2006,Martin,created it
 */
public class MOConnHandler extends PooledConnHandler {
    protected static final Log log = LogFactory.getLog(MOConnHandler.class);
    /**
     * 存放需要下发状态报告的信息
     */
    public static Hashtable reportData = new Hashtable();
    /**
     * 客户端连接
     */
    private Socket socketConn = null;
    private OutputStream out = null;
    private BufferedInputStream in = null;
    private static Object SYN_RECV_OBJ = new Object();

    /**
     * process 处理一个具体的客户端连接
     * 
     * @param socketConn 客户端的socket连接
     */
    public void process(Socket socketConn) {
        try {
            if (socketConn == null) {
                return;
            }
            this.socketConn = socketConn;
            byte[] allbytes = null;
            byte[] headbytes = null;
            byte[] bodybytes = null;
            if (TestConfConst.protocoltype.toLowerCase().equals(
                    TestConfConst.CMPP)) {
                headbytes = new byte[12];
            } else if (TestConfConst.protocoltype.toLowerCase().equals(
                    TestConfConst.SGIP)) {
                headbytes = new byte[20];
            }

            // 输出流
            out = socketConn.getOutputStream();
            // 输入流
            in = new BufferedInputStream(socketConn.getInputStream());
            // 从通道中读取了多少字节
            int commonLength = 0;
            while (true) {
                synchronized (SYN_RECV_OBJ) {
                    in.read(headbytes);
                    commonLength = TypeConvert.byte2int(headbytes, 0);
                    bodybytes = new byte[commonLength - headbytes.length];
                    in.read(bodybytes);
                    allbytes = new byte[commonLength];
                    // 处理移动CMPP协议
                    if (TestConfConst.protocoltype.toLowerCase().equals(
                            TestConfConst.CMPP)) {
                        System.arraycopy(headbytes, 0, allbytes, 0, 12);
                        System.arraycopy(bodybytes, 0, allbytes, 12,
                                bodybytes.length);
                        parseCMPP(allbytes);
                    }
                    // 处理联通SGIP协议
                    else if (TestConfConst.protocoltype.toLowerCase().equals(
                            TestConfConst.SGIP)) {
                        System.arraycopy(headbytes, 0, allbytes, 0, 20);
                        System.arraycopy(bodybytes, 0, allbytes, 20,
                                bodybytes.length);
                        parseSGIP(allbytes);
                    }
                }
            }

        } catch (Exception e) {
            log.error("error !!! handling a client:", e);
        }
    }

    //
    // /**
    // * 处理具体的信息
    // *
    // * @param byte[] 待处理的信息
    // * @return byte[] 未处理完剩余的消息
    // */
    // public byte[] parseMsg(byte[] buf) {
    // int alllength = buf.length;
    // int msglenth = TypeConvert.byte2int(buf, 0);
    // // 如果消息头返回的头信息中显示消息体为0长度，直接报告错误
    // if (0 == msglenth) {
    // log.error("Bad message package,please cheak the message head");
    // return new byte[0];
    // }
    // if (msglenth < 12) {
    // return buf;
    // }
    // // 表示一条信息处理不完
    // if (alllength < msglenth) {
    // return buf;
    // }
    // byte[] msgbytes = new byte[msglenth];
    // System.arraycopy(buf, 0, msgbytes, 0, msglenth);
    // // parse处理具体的业务
    // try {
    // // 处理移动CMPP协议
    // if (TestConfConst.protocoltype.toLowerCase().equals(
    // TestConfConst.CMPP)) {
    // parseCMPP(msgbytes);
    // }
    // // 处理联通SGIP协议
    // else if (TestConfConst.protocoltype.toLowerCase().equals(
    // TestConfConst.SGIP)) {
    // parseSGIP(msgbytes);
    // }
    // } catch (Exception ex) {
    // log.error("exception ", ex);
    // }
    // int spare = alllength - msglenth;
    // // 将剩余的全部拷贝到临时变量里面去
    // byte[] tmp = new byte[spare];
    // System.arraycopy(buf, msglenth, tmp, 0, spare);
    // if (spare < 12) {
    // return tmp;
    // }
    // msglenth = TypeConvert.byte2int(tmp, 0);
    // if (msglenth < spare) {
    // // 剩余空间超过一条消息，继续处理
    // return parseMsg(tmp);
    // } else {
    // return tmp;
    // }
    // }

    /**
     * 处理移动的cmpp协议
     * 
     * @param buf
     * @throws Exception
     */
    private void parseCMPP(byte[] buf) throws Exception {
        log.debug("------received sp message------");
        int commid = TypeConvert.byte2int(buf, 4);
        int sequence_ID = TypeConvert.byte2int(buf, 8);
        if (CMPPConstant.Submit_Command_Id == commid) {
            CMPP30SubmitMessage message = new CMPP30SubmitMessage(buf);
            log.debug(message.toString());
            // 回送sumitrepmessage
            CMPP30SubmitRepMessage submitRep = new CMPP30SubmitRepMessage(
                    sequence_ID, 0);
            byte[] submitRepbyte = submitRep.getBytes();
            log.debug("---------response sumitRep message------");
            out.write(submitRepbyte);
            out.flush();
            log.debug(submitRep.toString());
            // 是否需要状态报告
            int Registered_Delivery = message.getRegistered_Delivery();
            if (1 == Registered_Delivery) {
                String Service_Id = message.getService_Id();
                int tp_Pid = message.getTp_Pid();
                int Tp_Udhi = message.getTp_Udhi();
                int Msg_Fmt = message.getMsg_Fmt();
                String Msg_Src = message.getMsg_Src();
                String[] Dest_Terminal_Id = message.getDest_Terminal_Id();
                int Dest_Terminal_Type = message.getDest_Terminal_Type();
                String LinkID = message.getLinkID();
                // 构件deliver report消息
                CMPP30StatusRpt report = new CMPP30StatusRpt(submitRep
                        .getMsgId(), "DELIVRD", new Date(), new Date(),
                        Dest_Terminal_Id[0].trim(), 12);
                CMPP30DeliverMessage deliverMessage = new CMPP30DeliverMessage(
                        Msg_Src, Service_Id, tp_Pid, Tp_Udhi, Msg_Fmt,
                        Dest_Terminal_Id[0].trim(), Dest_Terminal_Type,
                        Registered_Delivery, report.getContents(), LinkID);
                log.debug("---------send report message------");
                out.write(deliverMessage.getBytes());
                out.flush();
                log.debug(deliverMessage.toString());
            }

        } else if (CMPPConstant.Deliver_Rep_Command_Id == commid) {
            CMPP30DeliverRepMessage message = new CMPP30DeliverRepMessage(buf);
            log.debug(message.toString());
        } else if (CMPPConstant.Connect_Command_Id == commid) {
            CMPP30ConnectMessage message = new CMPP30ConnectMessage(buf);
            log.debug(message.toString());
            // 回送CMPP30ConnectRepMessage
            // 效验用户名和密码0--正确2非法源地址3--认证错
            byte result = checkConnect(message);
            CMPP30ConnectRepMessage connectionrep = null;
            connectionrep = new CMPP30ConnectRepMessage(sequence_ID, result,
                    TestConfConst.login_Name, TestConfConst.login_Passowrd, 30);
            log.debug("---------response connectResponse message------");
            out.write(connectionrep.getBytes());
            out.flush();
            log.debug(connectionrep.toString());
            Timer timer = new Timer(true);
            // 启动发送deliver定时器
            timer.schedule(new SendDeliverTask(), new Date(), 1000);
            // 启动发送activetest定时器
            timer.schedule(new SendActiveTask(), new Date(), 5000);
        } else if (CMPPConstant.Active_Test_Command_Id == commid) {
            CMPP30ActiveTest activeTest = new CMPP30ActiveTest(buf);
            log.debug(activeTest.toString());
            CMPP30ActiveTestRep activeResp = new CMPP30ActiveTestRep(
                    sequence_ID, 0);
            log.debug("---------response ActiveRep message------");
            out.write(activeResp.getBytes());
            out.flush();
            log.debug(activeResp.toString());
        } else if (CMPPConstant.Active_Test_Rep_Command_Id == commid) {
            CMPP30ActiveTestRep testRep = new CMPP30ActiveTestRep(buf);
            log.debug(testRep.toString());
        }
    }

    public byte checkConnect(SGIPBindMessage message) {
        if (message.getLoginName().equals(TestConfConst.spLogin_Name)
                && message.getLoginPass()
                        .equals(TestConfConst.spLogin_Password)
                && message.getLoginType() == 1) {
            return 0;
        }
        return 1;
    }

    /**
     * 检查登陆名和密码
     * 
     * @param message
     * @return 0--正确 2--非法源地址 3--认证错误
     */
    public byte checkConnect(CMPP30ConnectMessage message) {
        // 地址
        String source_addr = message.getSource_Addr();
        // 用户名
        String shared_Secret = TestConfConst.spLogin_Password;
        Date timestamp = message.getTimestamp();
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss");
        // 日期
        String timestampStr = format.format(timestamp);
        // 2：非法源地址
        if (!TestConfConst.spLogin_Name.equals(source_addr)) {
            return 2;
        }
        int len = 0;
        if (shared_Secret != null)
            len = source_addr.length() + 19 + shared_Secret.length();
        else
            len = source_addr.length() + 19;
        byte tmpbuf[] = new byte[len];
        int tmploc = 0;
        System.arraycopy(source_addr.getBytes(), 0, tmpbuf, 0, source_addr
                .length());
        tmploc = source_addr.length() + 9;
        if (shared_Secret != null) {
            System.arraycopy(shared_Secret.getBytes(), 0, tmpbuf, tmploc,
                    shared_Secret.length());
            tmploc += shared_Secret.length();
        }
        System.arraycopy(timestampStr.getBytes(), 0, tmpbuf, tmploc, 10);
        byte[] result = new byte[16];
        SecurityTools.md5(tmpbuf, 0, len, result, 0);
        byte[] shared_Secretbytes = message.getShared_Secretbytes();
        for (int i = 0; i < 16; i++) {
            if (result[i] != shared_Secretbytes[i]) {
                return 3;
            }
        }
        return 0;
    }

    private void parseSGIP(byte[] buf) throws Exception {

        log.debug("------received sp message------");
        byte[] temp = new byte[4];
        System.arraycopy(buf, 4, temp, 0, 4);
        int commid = TypeConvert.Bytes4ToInt(temp);
        byte[] seqid = new byte[12];
        System.arraycopy(buf, 8, seqid, 0, 12);
        if (SGIPConstant.Submit_Command_Id == commid) {
            SGIPSubmitMessage submitMessage = new SGIPSubmitMessage(buf);
            log.debug(submitMessage.toString());
            SGIPSubmitRepMessage repMessage = new SGIPSubmitRepMessage(seqid, 0);
            log.debug("---------response sumitRep message------");
            out.write(repMessage.getBytes());
            out.flush();
            log.debug(repMessage.toString());
            if (1 == submitMessage.getReportFlag()
                    || 0 == submitMessage.getReportFlag()
                    || 3 == submitMessage.getReportFlag()) {
                String[] userNumber = submitMessage.getUserNumber();
                SGIPReportMessage reportMessage = null;
                for (int i = 0; i < submitMessage.getUserCount(); i++) {
                    // 如果需要状态报告，构造report消息，将消息保存在hashtable中,由另一个端口发送
                    reportMessage = new SGIPReportMessage(submitMessage
                            .getsubmitSequenceNumber(), 0, userNumber[i], 0, 0);
                    reportData.put("" + repMessage.getSequence_Id(),
                            reportMessage);
                }
            }
        } else if (SGIPConstant.Bind_Command_Id == commid) {
            SGIPBindMessage bindMessage = new SGIPBindMessage(buf);
            log.debug(bindMessage.toString());
            byte result = checkConnect(bindMessage);
            SGIPBindRepMessage bindRep = new SGIPBindRepMessage(seqid, result);
            log.debug("---------response bindResponse message------");
            out.write(bindRep.getBytes());
            out.flush();
            log.debug(bindRep.toString());
        } else if (SGIPConstant.ACTIVE_TEST == commid) {
            SGIPActiveTestMessage active = new SGIPActiveTestMessage(buf);
            log.debug(active.toString());
            SGIPActiveTestRepMessage activeRep = new SGIPActiveTestRepMessage(
                    seqid, 0);
            out.write(activeRep.getBytes());
            out.flush();
            log.debug(activeRep.toString());
        }

    }

    public class SendDeliverTask extends TimerTask {
        public void run() {
            try {
                if (null == socketConn || socketConn.isClosed()
                        || TestConfConst.deliverstate == 0) {
                    return;
                }

                CMPP30DeliverMessage deliver = null;
                int sleepTime = 1000 / TestConfConst.delivertimes;
                for (int i = 0; i < TestConfConst.delivertimes; i++) {
                    if (socketConn.isBound() && socketConn.isConnected()
                            && TestConfConst.deliverstate == 1) {

                        deliver = new CMPP30DeliverMessage(
                                TestConfConst.dest_Id,
                                TestConfConst.service_Id, 1, 1,
                                TestConfConst.msgFmt,
                                TestConfConst.src_terminal_Id,
                                TestConfConst.src_terminal_type, 0,
                                TestConfConst.msg_Content.getBytes(),
                                TestConfConst.linkID);
                        log.debug("---------send deliver message------");
                        out.write(deliver.getBytes());

                        out.flush();
                        MOServer.i++;
                        log.debug("处理了" + MOServer.i + "条deliver消息！");
                        log.debug(deliver.toString());
                        Thread.sleep(sleepTime);
                    }
                }

            } catch (IOException ioe) {
                log.error("ioexception", ioe);
                try {
                    // out.close();
                    // socketConn.close();
                    // socketConn = null;
                } catch (Exception ex) {

                }
            } catch (InterruptedException ex) {
                log.error("InterruptedException", ex);
            }
        }

    }

    public class SendActiveTask extends TimerTask {
        public void run() {
            try {
                if (null == socketConn || socketConn.isClosed()) {
                    return;
                }
                if (socketConn.isBound() && socketConn.isConnected()) {
                    CMPP30ActiveTest activetest = new CMPP30ActiveTest();
                    log.debug("---------send activetest message------");
                    out.write(activetest.getBytes());
                    out.flush();
                    log.debug(activetest.toString());
                }

            } catch (IOException ioe) {
                log.error("ioexception", ioe);
            }
        }

    }

}